@程序员,一文掌握 Web 应用中的图片优化技巧!
以下文章来源于前端漫游指南 ,作者fecoder
作者 | fecoder
责编 | 郭芮
npm install imagemin
npm install imagemin-pngquant
这里先安装imagemin库,再安装对应的png压缩库。
const imagemin = require('imagemin');
const imageminPngquant = require('imagemin-pngquant');
(async () => {
await imagemin(['images/*.png'], 'build/images', {
plugins: [
imageminPngquant({ quality: '65-80' })
]
});
console.log('Images optimized');
})();
我们可以在quailty一项决定压缩比率,65-80貌似是一个在压缩率和质量之间实现平衡的数值,腾讯AlloyTeam出品的gka图片处理工具,同样使用到了imagemin库,他们默认也是使用65-80的选项:gka代码。用它压缩一张png图片,我们看看效果如何:
npm install imagemin-mozjpeg
const imagemin = require('imagemin');
const imageminMozjpeg = require('imagemin-mozjpeg');
(async () => {
await imagemin(['images/*.jpg'], 'build/images', {
use: [
imageminMozjpeg({ quality: 65, progressive: true })
]
});
console.log('Images optimized');
})();
npm install imagemin-webpack-plugin
import ImageminPlugin from 'imagemin-webpack-plugin'
import imageminMozjpeg from 'imagemin-mozjpeg'
module.exports = {
plugins: [
new ImageminPlugin({
plugins: [
imageminMozjpeg({
quality: 100,
progressive: true
})
]
})
]
}
接着在Webpack配置文件中,引入自己需要的插件,使用方法完全相同。具体可参考GitHub的文档imagemin-webpack-plugin。
<li>
<img class="list-item-img" alt="loading" data-src='a.jpg'/>
</li>
<li>
<img class="list-item-img" alt="loading" data-src='b.jpg'/>
</li>
<li>
<img class="list-item-img" alt="loading" data-src='c.jpg'/>
</li>
<li>
<img class="list-item-img" alt="loading" data-src='d.jpg'/>
</li>
这样会导致图片无法加载,这当然不是我们的目的,我们想做的是,当IntersectionObserver监听到图片元素进入可视区域时,将data-src"还给"src属性,这样我们就可以实现图片加载了:
const observer = new IntersectionObserver(function(changes) {
changes.forEach(function(element, index) {
// 当这个值大于0,说明满足我们的加载条件了,这个值可通过rootMargin手动设置
if (element.intersectionRatio > 0) {
// 放弃监听,防止性能浪费,并加载图片。
observer.unobserve(element.target);
element.target.src = element.target.dataset.src;
}
});
});
function initObserver() {
const listItems = document.querySelectorAll('.list-item-img');
listItems.forEach(function(item) {
// 对每个list元素进行监听
observer.observe(item);
});
}
initObserver();
运行代码并观察控制台的Network,会发现图片随着可视区域的移动而加载,我们的目的达到了。
PS:额外介绍一个vue的图片懒加载组件vue-view-lazy,也是基于IntersectionObserver实现的。
auto:让浏览器自动决定是否进行懒加载,这其中的机制尚不明确。
lazy:明确地让浏览器对此图片进行懒加载,即当用户滚动到图片附近时才进行加载,但目前没有具体说明这个“附近”具体是多近。
eager:让浏览器立刻加载此图片,也不是此篇文章关注的功能。
if ("loading" in HTMLImageElement.prototype) {
// 没毛病
} else {
// .....
}
<img src="a.jpg" style="background: red;"/>
这样会先显示出红色背景,再渲染出真实的图片,重点来了,我们此时要借用工具为这张图片"配制"出合适的渐变背景色,以达到部分preview的效果,我们可以使用https://calendar.perfplanet.com/2018/gradient-image-placeholders/ 这篇文章中推荐的工具GIP进行转换,这里附上在线转换的地址https://tools.w3clubs.com/gip/。
经过转换后,我们得到了下面这串代码:
background: linear-gradient(
to bottom,
#1896f5 0%,
#2e6d14 100%
)
最终效果如下所示:
.bg {
background-image: url("bg.png");
width: 100px;
height: 100px;
background-size: 100% 100%;
}
@media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2)
{
.bg {
background-image: url("bg@2x.png") // 尺寸为200 * 200的图
}
}
这么做有两个好处,一是保证高像素密度的设备下,图片仍能保持应有的清晰度,二是防止在低像素密度的设备下加载大尺寸图片造成浪费。
<img width="320" src="bg@2x.png" srcset="bg.png 1x;bg@2x.png 2x"/>
这段代码的作用是:当设备像素密度,也就是dpr(devicePixelRatio)为1时,使用bg.png,为2时使用二倍图bg@2x.png。
依此类推,你可以根据需要设置多种精度下要加载的图片,如果没有命中,浏览器会选择最邻近的一个精度对应的图片进行加载。要注意:老旧的浏览器不支持srcset的特性,它会继续正常加载src属性引用的图像。
<picture>
<source srcset="bg.webp" type="image/webp">
<source srcset="bg.jpg" type="image/jpeg">
<img src="bg.jpg" alt="背景图">
</picture>
有了这段代码,浏览器会自动根据是否支持webp格式来选择加载哪张图片,若不支持,则会显示bg.jpg,如果浏览器连picture都不支持,那么会fallback到默认的img图片,这是必不可少的一个选项。
【END】
热 文 推 荐
☞大数据实践的 6 个阶段
☞Google 警告开发者:所有 Android App 需要三天的审核时间!
☞92年小哥绞尽脑汁骗得价值800万比特币, 破案后警方决定还给受害者